#include "main.h"
#include "adc.h"
#include "dma.h"
#include "gpio.h"
#include "iwdg.h"
#include "tim.h"
#include "usart.h"

#include "FreeRTOS.h" // IWYU pragma: export
#include "semphr.h"
#include "task.h"

#include "ds18b20.h"
#include "stream.h"
#include "subctrl.h"
#include "sys.h"
#include <cstddef>
#include <cstdint>
#include <cstring>

// 分控制器数据
static sub_control_t subctrl __attribute__((section(".bss.NoInit")));

// clang-format off
// 默认参数配置
const static sub_control_flash_t kDefaultFlash = {
    .init = 1,
    .ip = {192, 168, 11, 123},
    .config = {
        .att_val = ATTENUATION_MAX,
        .phase_val = PHASE_MAX / 2,
        .forward_pid = {
            .Kp = 0.00001f,
            .Ki = 0,
            .Kd = 0,
            .output_max = FORWARD_PID_OUTPUT_MAX,
            .output_min = 0,
            .error_total_threshold = 2000,
        },
        .reverse_pid = {
            .Kp = 0.00001f,
            .Ki = 0,
            .Kd = 0,
            .output_max = REVERSE_PID_OUTPUT_MAX,
            .output_min = 0,
            .error_total_threshold = 2000,
        }
    }
};
// clang-format on
// ADC通道映射
const static adc_pin_index_t kAdcMap[] = {
    {DL_JC2_ADC_CHANNEL, JB_IN2_ADC_CHANNEL},
    {DL_JC3_ADC_CHANNEL, JB_IN3_ADC_CHANNEL},
    {DL_JC4_ADC_CHANNEL, JB_IN4_ADC_CHANNEL},
};
// DS18B20配置
const static ds18b20_config_t kTempConfig[] = {
    {M_DQ2_GPIO_Port, M_DQ2_Pin, &subctrl.pa[kModule1st].temperature},
    {M_DQ3_GPIO_Port, M_DQ3_Pin, &subctrl.pa[kModule2nd].temperature},
    {M_DQ4_GPIO_Port, M_DQ4_Pin, &subctrl.pa[kModule3rd].temperature},
};
// 模块PD引脚配置
// clang-format off
const static pd_pin_index_t kPdConfig[] = {
    {M_PTT2_GPIO_Port, M_PTT2_Pin},
    {M_PTT3_GPIO_Port, M_PTT3_Pin},
    {M_PTT4_GPIO_Port, M_PTT4_Pin},
};
// clang-format on
// PA模块硬件配置
const static pa_module_hardware_config_t kPAmoduleHardwareConfig[] = {
    {&kAdcMap[kModule1st], &kTempConfig[kModule1st], &kPdConfig[kModule1st]},
    {&kAdcMap[kModule2nd], &kTempConfig[kModule2nd], &kPdConfig[kModule2nd]},
    {&kAdcMap[kModule3rd], &kTempConfig[kModule3rd], &kPdConfig[kModule3rd]},
};

// ADC原始数据
static uint16_t adc_raw_data[ADC_CHANNEL_NUM] = {0};

StreamProcessor Serial(&huart3);
StreamProcessor RS485(&huart1);
SubController SubControl(&subctrl, &Serial);

void SystemClock_Config(void);
void StreamOutCallback(uint8_t *data, uint16_t size, void *handle);
void RS485RunCallback(void *handle);
void SerialRunCallback(void *handle);

void vApplicationIdleHook()
{
#if !ENABLE_DEBUG_MODE
    HAL_IWDG_Refresh(&hiwdg);
#endif
    if (huart1.Instance->SR & USART_SR_ORE)
    {
        ATOMIC_SET_BIT(huart1.Instance->CR3, USART_CR3_DMAR);
        ATOMIC_SET_BIT(huart1.Instance->CR3, USART_CR3_EIE);
    }
    if (huart3.Instance->SR & USART_SR_ORE)
    {
        ATOMIC_SET_BIT(huart3.Instance->CR3, USART_CR3_DMAR);
        ATOMIC_SET_BIT(huart3.Instance->CR3, USART_CR3_EIE);
    }
}

void SerialTask(void *pvParameters)
{
    Serial.RegisterStreamOutCallback(StreamOutCallback);
    Serial.RegisterStreamRunCallback(SerialRunCallback);
    HAL_UARTEx_ReceiveToIdle_DMA(&huart3, Serial.payload_, DEFAULT_STREAM_PAYLOAD_SIZE);
    for (;;)
    {
        Serial.Run();
    }
}

void RS485Task(void *pvParameters)
{
    RS485.RegisterStreamOutCallback(StreamOutCallback);
    RS485.RegisterStreamRunCallback(RS485RunCallback);
    HAL_UARTEx_ReceiveToIdle_DMA(&huart1, RS485.payload_, DEFAULT_STREAM_PAYLOAD_SIZE);
    for (;;)
    {
        RS485.Run();
    }
}

void UpdateTask(void *pvParameters)
{
    static uint8_t index = 0;
    static uint16_t data_sample[ADC_SUM_NUM][ADC_CHANNEL_NUM] = {0};
    float data_avg[ADC_CHANNEL_NUM] = {0};

    HAL_ADCEx_Calibration_Start(&hadc1);
    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_raw_data, ADC_CHANNEL_NUM);
    for (;;)
    {
        memcpy(data_sample[index++], adc_raw_data, sizeof(adc_raw_data));
        if (index >= ADC_SUM_NUM)
            index = 0;

        for (uint8_t i = 0; i < ADC_CHANNEL_NUM; i++)
        {
            for (uint8_t j = 0; j < ADC_SUM_NUM; j++)
            {
                data_avg[i] += data_sample[j][i];
            }
            data_avg[i] /= ADC_SUM_NUM;
        }
        /* 更新电流 检波 温度数据 */
        /*MAX4080计算公式
         * Vout=Rsense * Iload * Av
         * I = V / (0.01 * 60)*/
        subctrl.current = data_avg[DL_JC1_ADC_CHANNEL] * (3.3f / 4095) / (SAMPLING_RESISTOR * MAX4080_GAIN);
        for (uint8_t i = 0; i < kModuleNum; i++)
        {
            subctrl.pa[i].current = (data_avg[subctrl.pa[i].hardware->adc_index->current] * (3.3f / 4095)) /
                                    (SAMPLING_RESISTOR * MAX4080_GAIN);
            subctrl.pa[i].rf_wave = data_avg[subctrl.pa[i].hardware->adc_index->rf_wave] * (3.3f / 4095);
        }
        vTaskDelay(50 / portTICK_PERIOD_MS);
    }
}

void AutoRunTask(void *pvParameters)
{
    TickType_t xLastWakeTime = xTaskGetTickCount();
    for (;;)
    {
        SubControl.ForwardLoop();
        vTaskDelay(100 / portTICK_PERIOD_MS);
        SubControl.ReverseLoop();
        xTaskDelayUntil(&xLastWakeTime, 200 / portTICK_PERIOD_MS);
    }
}

void MainTask(void *pvParameters)
{
    TickType_t xLastWakeTime = xTaskGetTickCount();
    for (;;)
    {
        LED_ON();
        DS18B20_GetStart();
        vTaskDelay(500 / portTICK_PERIOD_MS);
        DS18B20_GetTempe();
        LED_OFF();
        xTaskDelayUntil(&xLastWakeTime, 1000 / portTICK_PERIOD_MS);
    }
}

void InitTask(void *pvParameters)
{
    DS18B20_Init(kTempConfig);
    SubControl.Init(kPAmoduleHardwareConfig);
    xTaskCreate(UpdateTask, "update", 256, NULL, 3, NULL);
    xTaskCreate(AutoRunTask, "autorun", 512, NULL, 2, NULL);
    xTaskCreate(MainTask, "main", 256, NULL, 1, NULL);
    vTaskDelete(NULL);
}

int main(void)
{

    HAL_Init();

    SystemClock_Config();

    MX_GPIO_Init();
    MX_DMA_Init();
    MX_ADC1_Init();
    MX_USART1_UART_Init();
    MX_USART3_UART_Init();
    MX_TIM4_Init();

#if !ENABLE_DEBUG_MODE
    MX_IWDG_Init();
#endif

    xTaskCreate(SerialTask, "serial", 256, NULL, 5, NULL);
    xTaskCreate(RS485Task, "rs485", 256, NULL, 5, NULL);
    xTaskCreate(InitTask, "init", 256, NULL, 3, NULL);
    vTaskStartScheduler();
    while (1)
    {
    }
}

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.LSIState = RCC_LSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        Error_Handler();
    }
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
        Error_Handler();
    }
}

void Flash_Init(sub_control_flash_t *flash_p)
{
#if !ENABLE_DEBUG_MODE
    sub_control_flash_t temp;

    flash_p->init = DEFAULT_INITIAL_VALUE;
    Flash_Read(FLASH_START_ADDR, (uint32_t *)&temp, sizeof(sub_control_flash_t) / sizeof(uint32_t));
    if (temp.init != flash_p->init)
    {
        memcpy(flash_p, &kDefaultFlash, sizeof(sub_control_flash_t));
        Serial.Print("已加载默认参数\n");
        if (Flash_Write(FLASH_START_ADDR, (uint32_t *)flash_p, sizeof(sub_control_flash_t) / sizeof(uint32_t)))
            Serial.Print("闪存初始化失败\n");
        else
            Serial.Print("闪存已初始化\n");
    }
    else
    {
        memcpy(flash_p, &temp, sizeof(sub_control_flash_t));
        Serial.Print("已加载闪存参数\n"
                     "IP: %3d.%3d.%3d.%3d\n",
                     flash_p->ip[0], flash_p->ip[1], flash_p->ip[2], flash_p->ip[3]);
    }
#else
    memcpy(flash_p->ip, kDefaultIPAddress, sizeof(kDefaultIPAddress));
#endif
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Pos)
{
    if (huart->Instance == UART_SERIAL)
    {
        Serial.ReceiveComplete(Pos);
    }
    else if (huart->Instance == UART_RS485)
    {
        RS485.ReceiveComplete(Pos);
    }
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == UART_SERIAL)
    {
        Serial.SendComplete();
    }
    else if (huart->Instance == UART_RS485)
    {
        RS485.SendComplete();
    }
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == UART_SERIAL)
    {
        HAL_UARTEx_ReceiveToIdle_DMA(huart, Serial.payload_, DEFAULT_STREAM_PAYLOAD_SIZE);
    }
    else if (huart->Instance == UART_RS485)
    {
        HAL_UARTEx_ReceiveToIdle_DMA(huart, RS485.payload_, DEFAULT_STREAM_PAYLOAD_SIZE);
    }
}

void StreamOutCallback(uint8_t *data, uint16_t size, void *handle)
{
    HAL_UART_Transmit_DMA((UART_HandleTypeDef *)handle, data, size);
}

void SerialRunCallback(void *handle)
{
    if (Serial.payload_[0] == SERIAL_FRAME_HEADER)
    {
        if (ADD8_Check(Serial.payload_, Serial.size_))
        {
            Serial.Print("校验错误！\n");
            return;
        }
        switch (Serial.payload_[2])
        {
        case 0: /* 查询运行数据 */
            // clang-format off
            Serial.Print("\n编译日期: %s\n"
                         "IP地址: %d 状态: %s\n"
                         "自动运行: %s\n"
                         "复位次数: %d\n"
                         "衰减值: %5.2f\n"
                         "相位值: %5.2f\n"
                         "PA序号:     1     2     3\n"
                         "PA使能:     %d     %d     %d\n"
                         "PA温度: %5.2f %5.2f %5.2f\n"
                         "PA电流: %5.2f %5.2f %5.2f\n",
                         __DATE__,
                         subctrl.flash.ip[3], SubControl.GetStatus(),
                         subctrl.state.auto_run ? "开启" : "关闭",
                         subctrl.state.soft_reset_count,
                         subctrl.flash.config.att_val,
                         subctrl.flash.config.phase_val,
                         BIT_READ(subctrl.state.pa_enable, kModule1st),
                         BIT_READ(subctrl.state.pa_enable, kModule2nd),
                         BIT_READ(subctrl.state.pa_enable, kModule3rd),
                         subctrl.pa[kModule1st].temperature,
                         subctrl.pa[kModule2nd].temperature,
                         subctrl.pa[kModule3rd].temperature,
                         subctrl.pa[kModule1st].current,
                         subctrl.pa[kModule2nd].current,
                         subctrl.pa[kModule3rd].current);
            // 原始检波数据
            Serial.Print("PA检波: %5.2f %5.2f %5.2f\n",
                         subctrl.pa[kModule1st].rf_wave,
                         subctrl.pa[kModule2nd].rf_wave,
                         subctrl.pa[kModule3rd].rf_wave);
            // clang-format on
            break;
        case 1: /* 设定PA模块栅极电压 */
            Serial.Print("已废弃！\n");
            break;
        case 2: /* RF正向功率设定 */
            SubControl.SetTargetPower(*(float *)&Serial.payload_[3]);
            break;
        case 3: /* PID 参数设定 */
            Serial.Print("已废弃！\n");
            break;
        case 4: /* 功率映射配置 */
            Serial.Print("已废弃！\n");
            break;
        case 5: /* TCP参数配置 */
            SubControl.SetAddress(Serial.payload_[6]);
            break;
        case 6: /* 保护阈值参数配置 */
            Serial.Print("已废弃！\n");
            break;
        case 7: /* DAC限幅参数配置 */
            Serial.Print("已废弃！\n");
            break;
        case 8: /* 配置参数操作 */
            SubControl.SaveParameter();
            break;
        case 9: /* 模块复位 */
            SubControl.Restart(Serial.payload_[3]);
            break;
        case 10: /* 急停选项 */
            Serial.Print("已废弃！\n");
            break;
        }
    }
    else
    {
        Serial.Print("数据帧错误！\n");
    }
    HAL_UARTEx_ReceiveToIdle_DMA((UART_HandleTypeDef *)handle, Serial.payload_, DEFAULT_STREAM_PAYLOAD_SIZE);
}

void RS485RunCallback(void *handle)
{
    if (RS485.payload_[0] == RS485_FRAME_HEADER)
    {
        if (ADD8_Check(RS485.payload_, RS485.size_)) // 校验错误
            return;
        if (SubControl.CheckAddress(RS485.payload_[1])) // IP地址匹配
        {
            switch (RS485.payload_[2])
            {
            case RS485_TYPE_QUERY: /* 查询报文 */
                ADD8_Calculation((uint8_t *)&subctrl, sizeof(sub_control_t) - 1);
                RS485.Print((uint8_t *)&subctrl, sizeof(sub_control_t));
                break;
            case RS485_TYPE_SAVE_PARAMETER: /* 保存参数 */
                SubControl.SaveParameter();
                break;
            case RS485_TYPE_POWER: /* 设定功率 */
                SubControl.SetTargetPower(*(float *)&RS485.payload_[3]);
                break;
            case RS485_TYPE_PHASE: /* 设定相位 */
                SubControl.SetPhase(*(float *)&RS485.payload_[3]);
                break;
            case RS485_TYPE_ATTENUATION: /* 设定衰减 */
                SubControl.SetAttenuation(*(float *)&RS485.payload_[3]);
                break;
            case RS485_TYPE_AUTO_RUN: /* 设置自动运行 */
                SubControl.SetAutoRun(*(switch_state_t *)&RS485.payload_[3]);
                break;
            case RS485_TYPE_FORWAR_PID: /* 设定正向PID */
                SubControl.SetForwardPID(*(pid_config_t *)&RS485.payload_[3]);
                break;
            case RS485_TYPE_REVERSE_PID: /* 设定反向PID */
                SubControl.SetReversePID(*(pid_config_t *)&RS485.payload_[3]);
                break;
            }
        }
        else if (RS485.payload_[1] == RS485_UNIVERSAL_ADDRESS) // 通用地址
        {
            switch (RS485.payload_[2])
            {
            case RS485_TYPE_SAVE_PARAMETER: /* 保存参数 */
                SubControl.SaveParameter();
                break;
            case RS485_TYPE_POWER: /* 设定功率 */
                SubControl.SetTargetPower(*(float *)&RS485.payload_[3]);
                break;
            case RS485_TYPE_AUTO_RUN: /* 设置自动运行 */
                SubControl.SetAutoRun(*(switch_state_t *)&RS485.payload_[3]);
                break;
            }
        }
    }
    HAL_UARTEx_ReceiveToIdle_DMA((UART_HandleTypeDef *)handle, RS485.payload_, DEFAULT_STREAM_PAYLOAD_SIZE);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM3)
    {
        HAL_IncTick();
    }
}

void Error_Handler(void)
{
    __disable_irq();
    while (1)
    {
    }
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
